/**
 * 
 */
package com.fnic.pearl.scheduler.mod;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.log4j.Logger;

import com.fnic.pearl.scheduler.constant.TaskType;
import com.fnic.pearl.scheduler.constant.TestTaskStatus;
import com.fnic.pearl.scheduler.dao.SchedulerStore;
import com.fnic.pearl.scheduler.model.ProbeTaskStatus;
import com.fnic.pearl.scheduler.model.TestTask;

/**
 * probe 的测量任务的调度规则
 * 
 * @author HuHaiyang
 * @date 2013年9月9日
 */
public class TestTaskSchedulerRuler
{
    private static Logger LOG = Logger.getLogger(TestTaskSchedulerRuler.class);
    
    // 当前调度
    public static final int RESULT_CURR_SCHEDULER = 0;
    
    // 下次调度
    public static final int RESULT_NEXT_SCHEDULER = 1;
    
    // 不能再被调度
    public static final int RESULT_CANOT_SCHEDULER = 2;
    
    /**
     * 依据调度规则判断给定的测量任务当前是否可被调度执行
     * 
     * @param tt 测量任务
     */
    public static int canExecute(TestTask tt)
    {
        final Calendar now = Calendar.getInstance();
        if (tt.getRun() == TestTask.RUN_TIMING)
        {
            if (tt.getStartTime() == null)
            {
                LOG.info("scheduler rule - start time is null");
                return RESULT_CANOT_SCHEDULER;
            }
            
            Calendar startCal = Calendar.getInstance();
            startCal.setTime(tt.getStartTime());
            if (now.compareTo(startCal) < 0)
            {
                //LOG.info("scheduler rule - now < start");
                return RESULT_NEXT_SCHEDULER;
            }
        }
        
        if (tt.getEndTime() != null)
        {
            Calendar endCal = Calendar.getInstance();
            endCal.setTime(tt.getEndTime());
            if (now.compareTo(endCal) >= 0)
            {
                LOG.info("scheduler rule - now >= end");
                return RESULT_CANOT_SCHEDULER;
            }
        }
        
        if (tt.getCount() > 0 && tt.getExecNum() >= tt.getCount())
        {
            LOG.info("scheduler rule - exec num over");
            return RESULT_CANOT_SCHEDULER;
        }
        
        if (tt.getLastEndTime() != null)
        {
            Calendar lastEndCal = Calendar.getInstance();
            lastEndCal.setTime(tt.getLastEndTime());
            if ((now.getTimeInMillis() - lastEndCal.getTimeInMillis()) < (tt.getPeriodSec()*1000))
            {
                if (LOG.isDebugEnabled()) LOG.debug("scheduler rule - period not reach");
                return RESULT_NEXT_SCHEDULER;
            }
        }
        
        return RESULT_CURR_SCHEDULER;
    }
    
    /**
     * 判断指定的任务是否过期
     * 
     * @param tt 测量任务
     */
    public static boolean isExpire(TestTask tt)
    {
        if (tt.getEndTime() != null)
        {
            Calendar endCal = Calendar.getInstance();
            endCal.setTime(tt.getEndTime());
            Calendar now = Calendar.getInstance();
            if (now.compareTo(endCal) >= 0)
            {
                LOG.info("scheduler rule - now >= end");
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * 判断指定的任务当前是否已执行到 final 状态
     * 
     * @param taskId 任务ID
     * @return -1 不存在任务 0 表示非 final，1 表示 final
     */
    public static int testTaskFinal(long taskId)
    {
        TestTask tt = SchedulerStore.getInstance().getTestTask(taskId);
        if (tt == null)
        {
            return -1;
        }
        
        if (tt.getExecNum() >= tt.getCount() && tt.getCount() > 0)
        {
            return 1;
        }
        
        final Calendar now = Calendar.getInstance();
        if (tt.getEndTime() != null)
        {
            Calendar endCal = Calendar.getInstance();
            endCal.setTime(tt.getEndTime());
            if (now.compareTo(endCal) >= 0)
            {
                return 1;
            }
        }
        
        return 0;
    }
    
    /**
     * 判断指定的状态是否为 本次任务结束 状态
     */
    public static boolean isEndStatus(int status)
    {
        if (status == TestTaskStatus.S_FAILED_TASK_EXEC
                || status == TestTaskStatus.S_FAILED_TASK_HANGUP
                || status == TestTaskStatus.S_FAILED_TIMEOUT
                || status == TestTaskStatus.S_ISSUE_ES_SUCC
                || status == TestTaskStatus.S_ISSUE_REDIS_SUCC
                || status == TestTaskStatus.S_FAILED_TASK_ISSUE
                || status == TestTaskStatus.S_FAILED_PROBE_LOGOUT
                || status == TestTaskStatus.S_FAILED_ISSUE_REDIS
                || status == TestTaskStatus.S_FAILED_RESULT_ISSUE
                || status == TestTaskStatus.S_END)
        {
            return true;
        }
        
        return false;
    }
    
    /**
     * 判断指定的任务当前是否处于结束状态
     */
    public static boolean isEndStatus(ProbeTaskStatus pts)
    {
    	if (isEndStatus(pts.getStatus()))
    	{
    		return true;
    	}
    	
    	// 如果为 通用类型 的任务，则状态 EXEC_SUCC 就已经表示结束了
    	TestTask tt = SchedulerStore.getInstance().getTestTask(pts.getTaskId());
    	if (!tt.getTaskType().equals(TaskType.TEST_TASK) 
    			&& pts.getStatus() == TestTaskStatus.S_EXEC_SUCC)
    	{
    		return true;
    	}
    	
    	return false;
    }
    
    /**
     * 获取指定任务的上一个可能的状态列表
     */
    public static List<Integer> prevStatus(TestTask tt)
    {
        if (tt == null)
        {
            return null;
        }
        else if (TestTaskStatus.isUnknown(tt.getStatus()))
        {
            return null;
        }
        
        List<Integer> prevs = new ArrayList<Integer>();
        switch (tt.getStatus())
        {
        case TestTaskStatus.S_INIT:
            break;
            
        case TestTaskStatus.S_NEW_TASK:
            prevs.add(TestTaskStatus.S_INIT);
            break;
            
        case TestTaskStatus.S_WISSUE:
            prevs.add(TestTaskStatus.S_NEW_TASK);
            break;
            
        case TestTaskStatus.S_ISSUED:
            prevs.add(TestTaskStatus.S_WISSUE);
            break;
            
        case TestTaskStatus.S_RUNNING:
            prevs.add(TestTaskStatus.S_ISSUED);
            prevs.add(TestTaskStatus.S_FAILED_TASK_HANGUP);
            break;
            
        case TestTaskStatus.S_EXEC_SUCC:
            prevs.add(TestTaskStatus.S_RUNNING);
            prevs.add(TestTaskStatus.S_FAILED_TASK_HANGUP);
            break;
            
        case TestTaskStatus.S_ISSUE_REDIS_SUCC:
            prevs.add(TestTaskStatus.S_EXEC_SUCC);
            break;
            
        case TestTaskStatus.S_ISSUE_ES_SUCC:
            prevs.add(TestTaskStatus.S_EXEC_SUCC);
            break;
            
        //---------- failed status --------------
            
        case TestTaskStatus.S_FAILED_TASK_PARSE:
            prevs.add(TestTaskStatus.S_WISSUE);
            break;
            
        case TestTaskStatus.S_FAILED_TASK_EXEC:
            prevs.add(TestTaskStatus.S_RUNNING);
            break;
            
        case TestTaskStatus.S_FAILED_RESULT_ISSUE:
        case TestTaskStatus.S_FAILED_ISSUE_REDIS:
            prevs.add(TestTaskStatus.S_EXEC_SUCC);
            break;
            
        case TestTaskStatus.S_FAILED_TIMEOUT:
            prevs.add(TestTaskStatus.S_ISSUED);
            prevs.add(TestTaskStatus.S_RUNNING);
            prevs.add(TestTaskStatus.S_EXEC_SUCC);
            prevs.add(TestTaskStatus.S_FAILED_TASK_HANGUP);
            break;
        }
        
        return prevs;
    }
    
    /**
     * 获取在正常流程下，指定任务的下一个状态
     */
    public static int nextStatus(TestTask tt)
    {
        if (tt == null || TestTaskStatus.isUnknown(tt.getStatus()))
        {
            return TestTaskStatus.S_UNKNOWN;
        }
        
        switch (tt.getStatus())
        {
        case TestTaskStatus.S_INIT:
            return TestTaskStatus.S_WISSUE;
            
        case TestTaskStatus.S_WISSUE:
            return TestTaskStatus.S_ISSUED;
            
        case TestTaskStatus.S_ISSUED:
            return TestTaskStatus.S_RUNNING;
            
        case TestTaskStatus.S_RUNNING:
            return TestTaskStatus.S_EXEC_SUCC;
            
        case TestTaskStatus.S_EXEC_SUCC:
            return TestTaskStatus.S_ISSUE_REDIS_SUCC;
            
        case TestTaskStatus.S_ISSUE_REDIS_SUCC:
            return TestTaskStatus.S_END;
            
        case TestTaskStatus.S_ISSUE_ES_SUCC:
            return TestTaskStatus.S_END;
        }
        
        return TestTaskStatus.S_UNKNOWN;
    }
}
